// 导入所需模块
const fetch = require('node-fetch');
const dotenv = require('dotenv');
const logger = require('../utils/logger'); // 导入已有的logger

// 加载环境变量
dotenv.config();

class CCBFZService {
    constructor() {
        // 检查环境变量
        if (!process.env.CCBFZ_API_KEY) {
            logger.warn('警告: CCBFZ_API_KEY 未配置');
        }
        
        // API 配置 - 获取初始URL
        let apiUrl = process.env.CCBFZ_API_URL || 'http://10.252.132.112:8021/ai-service/ainlpllm/chat';
        
        // 记录原始URL
        logger.info(`[CCBFZ] 原始API URL: ${apiUrl}`);
        
        try {
            // 修复可能的URL格式问题
            // 1. 检查是否有":"后面跟着逗号分隔的IP地址问题: http://10:8021/,252,132,112/
            const commaIpPattern = /http:\/\/(\d+):(\d+)[\/,][\s,]*(\d+)[\s,]*(\d+)[\s,]*(\d+)/;
            if (commaIpPattern.test(apiUrl)) {
                apiUrl = apiUrl.replace(commaIpPattern, 'http://$1.$3.$4.$5:$2');
                logger.info(`[CCBFZ] URL格式修复 (逗号分隔IP): ${apiUrl}`);
            }
            
            // 2. 移除URL中的所有空格
            apiUrl = apiUrl.replace(/\s+/g, '');
            
            // 3. 确保主机名和端口之间的分隔符是正确的
            apiUrl = apiUrl.replace(/(\d+)\/(\d+)\//, '$1:$2/');
            
            // 4. 验证是否为有效URL格式
            if (!apiUrl.match(/^https?:\/\//)) {
                logger.warn(`[CCBFZ] URL不是以http或https开头，添加默认协议: ${apiUrl}`);
                apiUrl = 'http://' + apiUrl;
            }
            
            // 5. 尝试将URL解析为URL对象，验证格式
            const urlObj = new URL(apiUrl);
            apiUrl = urlObj.toString();
            logger.info(`[CCBFZ] 最终验证的API URL: ${apiUrl}`);
            
        } catch (error) {
            logger.error(`[CCBFZ] URL格式修复失败，使用默认URL: ${error.message}`);
            // 回退到默认URL
            apiUrl = 'http://10.252.132.112:8021/ai-service/ainlpllm/chat';
        }
        
        this.apiUrl = apiUrl;
        this.apiKey = process.env.CCBFZ_API_KEY || '1234872441562480640';
        
        logger.info(`[CCBFZ] 服务初始化完成，最终API URL: ${this.apiUrl}`);
    }

    /**
     * 记录日志
     * @param {string} level - 日志级别
     * @param {string} message - 日志信息
     * @param {Object} data - 额外数据（可选）
     */
    log(level, message, data = null) {
        // 对于敏感信息，不记录完整内容
        let safeData = data ? { ...data } : null;
        
        if (safeData) {
            // 如果包含API密钥，只显示前几位和后几位
            if (safeData.apiKey) {
                safeData.apiKey = `${safeData.apiKey.substring(0, 4)}...${safeData.apiKey.substring(safeData.apiKey.length - 4)}`;
            }
            
            // 如果数据太大，只记录摘要
            const stringified = JSON.stringify(safeData);
            if (stringified.length > 1000) {
                const preview = `${stringified.substring(0, 500)}...（共 ${stringified.length} 字符）`;
                logger[level](`[CCBFZ] ${message} - 数据过大，仅显示摘要: ${preview}`);
                return;
            }
            
            logger[level](`[CCBFZ] ${message} ${JSON.stringify(safeData)}`);
        } else {
            logger[level](`[CCBFZ] ${message}`);
        }
    }

    /**
     * 调用建行方舟满血版 CCBFZ R1 进行文档审核
     * @param {string} content - 需要审核的文档内容
     * @param {string} promptTemplate - 可选的提示词模板
     * @param {string} modelID - 模型ID，默认为满血版R1
     * @returns {Promise<Object>} - 返回审核结果
     */
    async reviewDocument(content, promptTemplate = null, modelID = "Deeseek-R1-671B_20250302") {
        this.log('info', '开始文档审核请求', { 
            contentLength: content?.length || 0, 
            hasPromptTemplate: !!promptTemplate,
            modelID
        });
        
        try {
            // 检查API_URL和API_KEY是否配置
            if (!process.env.CCBFZ_API_URL || !process.env.CCBFZ_API_KEY) {
                this.log('error', 'API URL或API密钥未配置');
                throw new Error('API URL或API密钥未配置，请在.env文件中设置CCBFZ_API_URL和CCBFZ_API_KEY');
            }
            
            // 移除对空内容的检查，允许content为空
            // if (!content) {
            //     this.log('error', '未提供审核内容');
            //     throw new Error('审核内容不能为空');
            // }

            // 构建默认提示词模板
            const defaultTemplate = `##角色:你是一位经验丰富的技术文档审核专家。
##任务:请仔细审核以下文档内容，评估其质量、完整性和专业性，并提供改进建议。

请从以下几个方面进行评审：
1. 文档结构与组织：评估文档的整体结构是否清晰、逻辑性强
2. 技术内容准确性：检查技术描述是否准确，术语使用是否正确
3. 完整性：评估文档是否包含所有必要的信息
4. 可读性：考察文档的语言表达、格式和排版
5. 改进建议：提供具体的改进建议

请首先进行深入思考，然后给出评审结果。评审结果应简明扼要，重点突出需要改进的地方。`;

            // 使用提供的模板或默认模板，检查提示模板中是否包含{content}占位符
            let finalPrompt = '';
            if (promptTemplate && promptTemplate.includes('{content}')) {
                // 如果提示词中有{content}占位符，则替换为实际内容
                finalPrompt = promptTemplate.replace('{content}', content || '');
            } else if (!content) {
                // 如果content为空，则直接使用模板而不添加内容部分
                finalPrompt = promptTemplate || defaultTemplate;
            } else {
                // 否则按原有方式拼接
                finalPrompt = (promptTemplate || defaultTemplate) + "\n\n审核内容如下：\n\n" + content;
            }
            
            // 添加长度检查，限制在120K字符以内
            const MAX_PROMPT_LENGTH = 120 * 1024; // 120K字符
            if (finalPrompt.length > MAX_PROMPT_LENGTH) {
                this.log('warn', `提示词过长: ${finalPrompt.length} 字符，超过了 ${MAX_PROMPT_LENGTH} 字符的限制，尝试截断`);
                
                // 计算内容应该保留的长度
                const templateLength = promptTemplate ? promptTemplate.length : defaultTemplate.length;
                const maxContentLength = MAX_PROMPT_LENGTH - templateLength - 100; // 保留额外100字符空间
                
                // 截断内容，处理content为空的情况
                let truncatedContent = '';
                if (content) {
                    truncatedContent = content.substring(0, maxContentLength) + 
                        `...\n[内容过长，已截断。原内容共${content.length}字符，已截断为${maxContentLength}字符]`;
                }
                
                // 重新构建提示词
                if (promptTemplate && promptTemplate.includes('{content}')) {
                    finalPrompt = promptTemplate.replace('{content}', truncatedContent);
                } else if (!content) {
                    // 如果content为空，则直接使用模板
                    finalPrompt = promptTemplate || defaultTemplate;
                } else {
                    finalPrompt = (promptTemplate || defaultTemplate) + "\n\n审核内容如下：\n\n" + truncatedContent;
                }
                
                this.log('warn', `提示词已截断为 ${finalPrompt.length} 字符`);
            }
            
            this.log('debug', '已构建最终提示词', { 
                promptLength: finalPrompt.length,
                useDefaultTemplate: !promptTemplate
            });

            // 生成请求ID
            const traceId = `test-${Date.now()}`;
            this.log('debug', `生成请求ID: ${traceId}`);
            
            // 构建消息体
            const messages = [
                { role: "system", content: "你是一位经验丰富的技术文档审核专家" },
                { role: "user", content: finalPrompt }
            ];
            
            // 构建请求头
            const headers = {
                "Tx-Code": "TA238FZ01",
                "Sec-Node-No": "400136",
                "Trace-Id": traceId,
                "Access_Key_Id": this.apiKey,
                "Host": "ai-scorpion.itech.ccb.com",
                "Content-Type": "application/json"
            };
            
            // 构建请求体数据
            const dataCntnt = {
                userId: "test",
                sessionId: "123455",
                messages: messages,
                countTokens: true,
                echo: true,
                stream: false,
                model_config: {
                    model: modelID, // 使用传入的模型ID
                    temperature: 0.6,
                    top_p: 0.9,
                    top_k: 20,
                    max_tokens: 40960000
                }
            };
            
            // 构建完整请求体
            const requestBody = {
                msgHead: {
                    sys_evt_trace_id: traceId
                },
                Data_cntnt: JSON.stringify(dataCntnt),
                Fst_Attr_Rmrk: this.apiKey
            };
            
            const requestBodyJson = JSON.stringify(requestBody);
            
            // 生成等效的curl命令用于调试
            let curlCommand = `curl -X POST "${this.apiUrl}" \\\n`;
            for (const [key, value] of Object.entries(headers)) {
                curlCommand += `  -H "${key}: ${value}" \\\n`;
            }
            curlCommand += `  -d '${requestBodyJson.replace(/'/g, "\\'")}'\n`;
            
            // 记录curl命令到日志，方便排查问题
            this.log('info', `CCBFZ API调用的curl命令:\n${curlCommand}`);
            
            // 打印URL，确认格式正确
            this.log('info', `请求URL: ${this.apiUrl}`);
            
            this.log('info', '准备发送API请求', { 
                url: this.apiUrl,
                traceId: traceId,
                messageCount: messages.length,
                requestBodySize: requestBodyJson.length
            });
            
            // 记录请求开始时间
            const requestStartTime = Date.now();
            
            // 发送请求
            const response = await fetch(this.apiUrl, {
                method: 'POST',
                headers: headers,
                body: requestBodyJson
            });
            
            // 计算请求耗时
            const requestDuration = Date.now() - requestStartTime;
            
            this.log('info', `API请求完成，耗时: ${requestDuration}ms`, { 
                status: response.status,
                statusText: response.statusText,
                headers: Object.fromEntries([...response.headers])
            });
            
            // 检查响应状态
            if (!response.ok) {
                // 尝试解析响应内容提供更详细的错误信息
                let errorDetails = "";
                try {
                    const errorText = await response.text();
                    errorDetails = errorText.substring(0, 500); // 只取前500个字符避免日志过长
                    this.log('error', `HTTP错误响应内容: ${errorDetails}`);
                } catch (textError) {
                    this.log('error', `无法获取错误响应内容: ${textError.message}`);
                }
                
                const errorMessage = `HTTP 错误，状态码: ${response.status}, ${response.statusText}`;
                this.log('error', errorMessage, {
                    status: response.status,
                    statusText: response.statusText,
                    errorDetails: errorDetails
                });
                
                throw new Error(`${errorMessage}${errorDetails ? ': ' + errorDetails : ''}`);
            }
            
            // 尝试解析响应JSON
            let responseData;
            try {
                responseData = await response.json();
                this.log('debug', '成功解析响应JSON');
            } catch (jsonError) {
                // 尝试获取原始响应内容
                const rawResponse = await response.text();
                const previewResponse = rawResponse.substring(0, 500); // 取前500个字符
                this.log('error', `解析JSON响应失败: ${jsonError.message}`, {
                    responsePreview: previewResponse
                });
                throw new Error(`解析JSON响应失败: ${jsonError.message}，响应内容: ${previewResponse}`);
            }
            
            // 检查API状态
            if (responseData['C-API-Status'] !== '00') {
                this.log('error', `API 调用失败: ${responseData['C-Response-Desc']}`, {
                    apiStatus: responseData['C-API-Status'],
                    responseDesc: responseData['C-Response-Desc']
                });
                throw new Error(`API 调用失败: ${responseData['C-Response-Desc']}`);
            }
            
            // 解析响应体
            const responseBody = responseData['C-Response-Body'];
            
            // 检查响应码
            if (responseBody.codeid !== '20000') {
                this.log('error', `业务处理失败，错误码: ${responseBody.codeid}`, {
                    codeid: responseBody.codeid
                });
                throw new Error(`业务处理失败，错误码: ${responseBody.codeid}`);
            }
            
            this.log('debug', '响应状态正常，开始解析数据');
            
            // 解析返回的数据
            const resultData = JSON.parse(responseBody.Data_Enqr_Rslt);
            this.log('debug', '成功解析返回数据', {
                hasChoices: resultData.choices && resultData.choices.length > 0,
                totalTokens: resultData.usage ? resultData.usage.total_tokens : 'unknown'
            });
            
            // 提取结果
            if (resultData.choices && resultData.choices.length > 0) {
                const choice = resultData.choices[0];
                const messages = choice.messages;
                
                const result = {
                    result: messages.content || "无内容返回",
                    thinking: messages.reasoning_content || "无思考过程"
                };
                
                this.log('info', '文档审核完成', {
                    resultLength: result.result.length,
                    thinkingLength: result.thinking.length,
                    finishReason: choice.finish_reason || 'unknown'
                });
                
                return result;
            } else {
                this.log('error', 'API 响应格式异常：未找到有效的选择项', resultData);
                throw new Error('API 响应格式异常：未找到有效的选择项');
            }

        } catch (error) {
            this.log('error', `调用 CCBFZ R1 API 失败: ${error.message}`, {
                stack: error.stack,
                name: error.name
            });
            throw error;
        }
    }
    
    /**
     * 处理流式响应
     * @param {ReadableStream} stream - 流式响应
     * @returns {Promise<Object>} - 返回处理后的结果
     */
    async handleStreamResponse(stream) {
        this.log('info', '开始处理流式响应');
        
        let content = '';
        let reasoningContent = '';
        let isReasoning = true; // 开始时我们接收的是思维链内容
        let chunkCount = 0;
        
        const reader = stream.getReader();
        
        try {
            while (true) {
                const { done, value } = await reader.read();
                if (done) {
                    this.log('debug', '流式响应读取完成');
                    break;
                }
                
                chunkCount++;
                
                // 将 Uint8Array 转换为字符串
                const chunk = new TextDecoder().decode(value);
                
                this.log('debug', `收到第 ${chunkCount} 个数据块`, {
                    chunkSize: value.length,
                    chunkPreview: chunk.length > 100 ? chunk.substring(0, 100) + '...' : chunk
                });
                
                // 处理 SSE 格式数据
                const lines = chunk.split('\n');
                
                for (const line of lines) {
                    if (line.startsWith('data:')) {
                        const jsonStr = line.substring(5).trim();
                        
                        try {
                            const data = JSON.parse(jsonStr);
                            
                            if (data['C-API-Status'] === '00') {
                                const responseBody = data['C-Response-Body'];
                                if (responseBody.codeid === '20000') {
                                    const resultData = JSON.parse(responseBody.Data_Enqr_Rslt);
                                    
                                    if (resultData.choices && resultData.choices.length > 0) {
                                        const messages = resultData.choices[0].messages;
                                        
                                        // 检查是思维链还是内容
                                        if (messages.reasoning_content) {
                                            reasoningContent += messages.reasoning_content;
                                            this.log('debug', '接收到思维链内容', {
                                                newContentLength: messages.reasoning_content.length,
                                                totalReasoningLength: reasoningContent.length
                                            });
                                        } else if (messages.content) {
                                            isReasoning = false; // 现在我们开始接收内容
                                            content += messages.content;
                                            this.log('debug', '接收到响应内容', {
                                                newContentLength: messages.content.length,
                                                totalContentLength: content.length
                                            });
                                        }
                                        
                                        // 检查是否是最后一个响应
                                        if (resultData.choices[0].finish_reason) {
                                            this.log('debug', `流式响应结束原因: ${resultData.choices[0].finish_reason}`);
                                        }
                                    }
                                } else {
                                    this.log('warn', `响应体中的codeid不是成功状态: ${responseBody.codeid}`);
                                }
                            } else {
                                this.log('warn', `API状态异常: ${data['C-API-Status']}`, {
                                    responseDesc: data['C-Response-Desc']
                                });
                            }
                        } catch (parseError) {
                            this.log('error', `解析SSE数据行失败: ${parseError.message}`, {
                                line: line,
                                jsonStr: jsonStr
                            });
                        }
                    }
                }
            }
            
            this.log('info', '流式响应处理完成', {
                contentLength: content.length,
                reasoningLength: reasoningContent.length,
                totalChunks: chunkCount
            });
            
            return {
                result: content,
                thinking: reasoningContent
            };
            
        } catch (error) {
            this.log('error', `处理流式响应失败: ${error.message}`, {
                stack: error.stack
            });
            throw error;
        }
    }
}

// 导出服务类
module.exports = CCBFZService; 